namespace CollabApp.Domain.ValueObjects;

/// <summary>
/// 玩家颜色值对象 - 表示游戏中玩家的专属颜色
/// 不可变对象，确保颜色的一致性和有效性
/// </summary>
public sealed class PlayerColor : IEquatable<PlayerColor>
{
    /// <summary>
    /// 颜色的十六进制值（如：#FF0000）
    /// </summary>
    public string Value { get; }
    
    /// <summary>
    /// 颜色名称（如：红色、蓝色）
    /// </summary>
    public string Name { get; }

    /// <summary>
    /// RGB值
    /// </summary>
    public (byte R, byte G, byte B) RGB { get; }

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="value">十六进制颜色值</param>
    /// <param name="name">颜色名称</param>
    private PlayerColor(string value, string name)
    {
        if (!IsValidHexColor(value))
            throw new ArgumentException("无效的十六进制颜色格式", nameof(value));
        
        Value = value.ToUpper();
        Name = name;
        RGB = HexToRgb(Value);
    }

    /// <summary>
    /// 预定义的游戏颜色集合 - 确保色彩区分度
    /// </summary>
    public static readonly PlayerColor Red = new("#FF4444", "红色");
    public static readonly PlayerColor Blue = new("#4488FF", "蓝色");
    public static readonly PlayerColor Green = new("#44FF44", "绿色");
    public static readonly PlayerColor Yellow = new("#FFFF44", "黄色");
    public static readonly PlayerColor Purple = new("#FF44FF", "紫色");
    public static readonly PlayerColor Orange = new("#FF8844", "橙色");
    public static readonly PlayerColor Cyan = new("#44FFFF", "青色");
    public static readonly PlayerColor Pink = new("#FF88AA", "粉色");

    /// <summary>
    /// 所有可用的玩家颜色
    /// </summary>
    public static readonly PlayerColor[] AllColors = 
    {
        Red, Blue, Green, Yellow, Purple, Orange, Cyan, Pink
    };

    /// <summary>
    /// 从十六进制值创建颜色
    /// </summary>
    /// <param name="hexValue">十六进制颜色值</param>
    /// <param name="name">颜色名称（可选）</param>
    /// <returns>玩家颜色对象</returns>
    public static PlayerColor FromHex(string hexValue, string? name = null)
    {
        return new PlayerColor(hexValue, name ?? "自定义颜色");
    }

    /// <summary>
    /// 根据玩家索引获取颜色
    /// </summary>
    /// <param name="playerIndex">玩家索引（0-7）</param>
    /// <returns>对应的颜色</returns>
    public static PlayerColor GetByPlayerIndex(int playerIndex)
    {
        if (playerIndex < 0 || playerIndex >= AllColors.Length)
            throw new ArgumentOutOfRangeException(nameof(playerIndex), 
                $"玩家索引必须在0-{AllColors.Length - 1}之间");
        
        return AllColors[playerIndex];
    }

    /// <summary>
    /// 获取随机颜色
    /// </summary>
    /// <returns>随机的玩家颜色</returns>
    public static PlayerColor GetRandom()
    {
        var random = new Random();
        return AllColors[random.Next(AllColors.Length)];
    }

    /// <summary>
    /// 获取指定颜色的轻微变体（用于团队模式）
    /// </summary>
    /// <param name="brightness">亮度调整（-50到50）</param>
    /// <returns>调整后的颜色</returns>
    public PlayerColor GetVariant(int brightness = 20)
    {
        brightness = Math.Max(-50, Math.Min(50, brightness));
        
        var newR = (byte)Math.Max(0, Math.Min(255, RGB.R + brightness));
        var newG = (byte)Math.Max(0, Math.Min(255, RGB.G + brightness));
        var newB = (byte)Math.Max(0, Math.Min(255, RGB.B + brightness));
        
        var newHex = $"#{newR:X2}{newG:X2}{newB:X2}";
        return new PlayerColor(newHex, $"{Name}变体");
    }

    /// <summary>
    /// 检查颜色对比度是否足够（用于文字显示）
    /// </summary>
    /// <param name="backgroundColor">背景色</param>
    /// <returns>是否有足够对比度</returns>
    public bool HasGoodContrast(PlayerColor backgroundColor)
    {
        if (backgroundColor == null) throw new ArgumentNullException(nameof(backgroundColor));
        
        // 计算相对亮度
        var luminance1 = GetRelativeLuminance();
        var luminance2 = backgroundColor.GetRelativeLuminance();
        
        // 计算对比度比率
        var brighter = Math.Max(luminance1, luminance2);
        var darker = Math.Min(luminance1, luminance2);
        var contrast = (brighter + 0.05) / (darker + 0.05);
        
        return contrast >= 4.5; // WCAG AA标准
    }

    /// <summary>
    /// 获取建议的文字颜色（黑色或白色）
    /// </summary>
    /// <returns>建议的文字颜色</returns>
    public string GetRecommendedTextColor()
    {
        var luminance = GetRelativeLuminance();
        return luminance > 0.5 ? "#000000" : "#FFFFFF";
    }

    /// <summary>
    /// 验证十六进制颜色格式
    /// </summary>
    private static bool IsValidHexColor(string value)
    {
        if (string.IsNullOrWhiteSpace(value)) return false;
        if (!value.StartsWith("#")) return false;
        if (value.Length != 7) return false;
        
        return value.Skip(1).All(c => 
            (c >= '0' && c <= '9') || 
            (c >= 'A' && c <= 'F') || 
            (c >= 'a' && c <= 'f'));
    }

    /// <summary>
    /// 将十六进制转换为RGB
    /// </summary>
    private static (byte R, byte G, byte B) HexToRgb(string hex)
    {
        var hexValue = hex.Substring(1);
        var r = Convert.ToByte(hexValue.Substring(0, 2), 16);
        var g = Convert.ToByte(hexValue.Substring(2, 2), 16);
        var b = Convert.ToByte(hexValue.Substring(4, 2), 16);
        return (r, g, b);
    }

    /// <summary>
    /// 计算相对亮度（用于对比度计算）
    /// </summary>
    private double GetRelativeLuminance()
    {
        var r = RGB.R / 255.0;
        var g = RGB.G / 255.0;
        var b = RGB.B / 255.0;

        r = r <= 0.03928 ? r / 12.92 : Math.Pow((r + 0.055) / 1.055, 2.4);
        g = g <= 0.03928 ? g / 12.92 : Math.Pow((g + 0.055) / 1.055, 2.4);
        b = b <= 0.03928 ? b / 12.92 : Math.Pow((b + 0.055) / 1.055, 2.4);

        return 0.2126 * r + 0.7152 * g + 0.0722 * b;
    }

    /// <summary>
    /// 颜色相等性比较
    /// </summary>
    public bool Equals(PlayerColor? other)
    {
        if (other is null) return false;
        if (ReferenceEquals(this, other)) return true;
        return Value.Equals(other.Value, StringComparison.OrdinalIgnoreCase);
    }

    public override bool Equals(object? obj) => Equals(obj as PlayerColor);

    public override int GetHashCode() => Value.GetHashCode();

    public override string ToString() => $"{Name} ({Value})";

    public static bool operator ==(PlayerColor? left, PlayerColor? right)
    {
        return left?.Equals(right) ?? right is null;
    }

    public static bool operator !=(PlayerColor? left, PlayerColor? right)
    {
        return !(left == right);
    }

    /// <summary>
    /// 隐式转换为字符串
    /// </summary>
    public static implicit operator string(PlayerColor color) => color.Value;
}
